package demoMod.stsconsole;

import demoMod.stsconsole.commands.AbstractCommand;
import demoMod.stsconsole.config.SpireConfig;
import demoMod.stsconsole.enums.ErrType;
import demoMod.stsconsole.helpers.LocalizedStrings;
import demoMod.stsconsole.helpers.PromptHelper;
import demoMod.stsconsole.interfaces.ISubscriber;
import demoMod.stsconsole.interfaces.ReloadStringsSubscriber;
import demoMod.stsconsole.interfaces.TriConsumer;
import demoMod.stsconsole.saves.RootSaver;
import demoMod.stsconsole.settings.ConsoleSettings;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class ConsoleEntry implements ReloadStringsSubscriber {
    public static boolean exit = false;
    private static List<String> uiStrings;
    public static final List<ISubscriber> subscribers = new ArrayList<ISubscriber>() {
        @Override
        public boolean add(ISubscriber subscriber) {
            if (size() > 0 && !needSortSubscribers) {
                needSortSubscribers = subscriber.getPriority() < get(size() - 1).getPriority();
            }
            return super.add(subscriber);
        }
    };

    public static final List<ISubscriber> addLater = new ArrayList<>();
    private static boolean needSortSubscribers = false;
    public static final List<ISubscriber> removeLater = new ArrayList<>();
    public static final RootSaver rootSaver = new RootSaver();
    public static SpireConfig config = new SpireConfig("settings.properties");
    private static final Scanner sc = new Scanner(System.in);

    public ConsoleEntry() {
        subscribers.add(this);
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        new ConsoleEntry();
        if (config.hasKey("language")) ConsoleSettings.language = config.getString("language");
        LocalizedStrings.initialize();

        System.out.println(uiStrings.get(0) + ConsoleSettings.language);
        System.out.println(uiStrings.get(3));
        while (!exit) {
            System.out.print(PromptHelper.getPrompt() + ">");
            String cmdLine = sc.nextLine(); //读键盘输入
            String cmd = cmdLine.split(" ")[0]; //获得命令
            String[] tmp = cmdLine.split(" ", 2);
            String[] argv;
            if (tmp.length >= 2) {
                argv = tmp[1].split(" "); //获得参数
            } else {
                argv = new String[0];
            }
            char[] cmdChars = cmd.toCharArray();

            if (cmdChars.length == 0) continue;

            cmdChars[0] = Character.toUpperCase(cmdChars[0]); //命令首字母大写得到对应类
            cmd = new String(cmdChars);

            Class<? extends AbstractCommand> cls;
            try {
                cls = (Class<? extends AbstractCommand>) Class.forName("demoMod.stsconsole.commands." + cmd);
            } catch (ClassNotFoundException e) {
                System.out.println(uiStrings.get(1));
                continue;
            }
            AbstractCommand command = cls.newInstance(); //反射获取类
            if (command.requiredPrompt(PromptHelper.getPrompt())) { //如果前置条件满足
                command.execute(argv, sc); //执行命令
            } else {
                command.errMsg(ErrType.WRONG_PROMPT);
            }
            subscribers.addAll(addLater);
            subscribers.removeAll(removeLater);
            addLater.clear();
            removeLater.clear();
        }
        sc.close();
        System.out.println(uiStrings.get(2));
    }

    public static void triggerSubscribers(Class<? extends ISubscriber> cls, String methodName, Class<?>[] paramTypes, Object[] params, TriConsumer<Method, Object[], ISubscriber> operations) {
        if (needSortSubscribers) ConsoleEntry.subscribers.sort(ISubscriber::compareTo);
        needSortSubscribers = false;
        for (ISubscriber subscriber : ConsoleEntry.subscribers) {
            if (cls.isInstance(subscriber) && subscriber.enabled(cls)) {
                try {
                    Method method = cls.getDeclaredMethod(methodName, paramTypes);
                    method.setAccessible(true);
                    operations.accept(method, params, subscriber);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 无参无返回值无额外操作
     * @param cls 要触发的事件
     * @param methodName 方法名称
     */
    public static void triggerSubscribers(Class<? extends ISubscriber> cls, String methodName) {
        triggerSubscribers(cls, methodName, new Class<?>[0], new Object[0], (method, params, subscriber) -> {
            try {
                method.invoke(subscriber, params);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 有参无返回值无额外操作
     * @param cls 要触发的事件
     * @param methodName 方法名称
     * @param paramTypes 参数类型
     * @param params 参数列表
     */
    public static void triggerSubscribers(Class<? extends ISubscriber> cls, String methodName, Class<?>[] paramTypes, Object[] params) {
        triggerSubscribers(cls, methodName, paramTypes, params, (method, params1, subscriber) -> {
            try {
                method.invoke(subscriber, params1);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    public void onReloadStrings() {
        uiStrings = LocalizedStrings.getUIStrings("ConsoleEntry");
    }

    public static Scanner getScanner() {
        return sc;
    }
}
